import 'reflect-metadata'
import {
    Store, StoreOptions,
    Module,
    Commit, CommitOptions,
    Dispatch, DispatchOptions, ActionContext
} from 'vuex'


class StoreContext {
    _pre_context?: StoreContext
    state: { [key: string]: any } = {}
    getters: { [key: string]: any } = {}
    rootState: { [key: string]: any } = {}
    rootGetters: { [key: string]: any } = {}
    dispatch: Dispatch = async (type: string, payload?: any, options?: DispatchOptions) => {
        throw new Error("请不要在不恰当的位置调用。[缺少必要的上下文]");
    }
    commit: Commit = (type: string, payload?: any, options?: CommitOptions) => {
        throw new Error("请不要在不恰当的位置调用。[缺少必要的上下文]");
    }
}

/** 用于管理上下文的获取句柄 */
class StoreContextHandle {
    context?: StoreContext
    store?: Store<any>
    push(option: StoreContextOption) {
        let new_context = Object.assign(new StoreContext, option);

        new_context._pre_context = this.context;
        this.context = new_context;
    }
    pop() {
        if (this.context) {
            this.context = this.context._pre_context;
        }
    }
}

class StoreContextOption {
    state?: any
    getters?: any
    rootState?: any
    rootGetters?: any
    dispatch?: Dispatch
    commit?: Commit
}

class StateType {
    [key: string]: any
}

/** 状态节点 */
export class StoreItem {


    /** 该层状态的名字 */
    __store_name: string = "";
    /** 上级状态 */
    __parent?: StoreItem;
    __children: StoreItem[] = [];
    __context_handle?: StoreContextHandle;
    __module_definition?: StoreOptions<StateType>;

    [key: string]: any;

    constructor() {
    }

    get __context(): StoreContext | undefined {
        return this.__context_handle ? this.__context_handle.context : undefined;
    }

    __root_object?: StoreItem;
    /** 获取根模块，使用该对像操作，将调用根方法 */
    get root(): StoreItem | undefined {
        return this.__parent ? this.__parent.root : this.__root_object;
    }

    //#region 路径

    private __path_string?: string
    /** 获取路径 */
    get __path(): string {
        if (!this.__path_string) {
            this.__path_string = (this.__parent ? this.__parent.__path : "")
                + (this.__store_name ? this.__store_name + "/" : "");
        }
        return this.__path_string;
    }

    //#endregion

    get __store(): Store<any> | undefined {
        return this.__context_handle ? this.__context_handle.store : undefined;
    }

    get __state(): any {
        return this.__parent
            ? this.__parent.__state[this.__store_name]
            : this.__store ? this.__store.state : undefined;
    }

    get __rootState(): any {
        return this.__parent
            ? (this.__parent.__rootState
                ? this.__parent.__rootState[this.__store_name]
                : undefined
            )
            : this.__context ? this.__context.rootState : undefined
    }

    /**
     * 初始化
     * @param store 关联
     */
    __init(store: Store<any>) {
        if (this.__context_handle && this.__context_handle.store) return;

        if (!this.__parent) {
            // 没有父节点时，创建上下文
            this.__context_handle = new StoreContextHandle;
            this.__context_handle.store = store;
            if (this.__root_object) {
                this.__root_object.__context_handle = this.__context_handle;
            }
        }
        else {
            this.__context_handle = this.__parent.__context_handle;
            if (this.__root_object) {
                this.__root_object.__context_handle = this.__parent.__context_handle;
            }
        }

        this.__children.forEach(item => item.__init(store));
    }

    __with(context_option: StoreContextOption, run: (_store_item: StoreItem) => any): any {

        if (!this.__context_handle) {
            var handle = new StoreContextHandle;
            this.__context_handle = new StoreContextHandle;
        }

        this.__context_handle.push(context_option);

        let ret: any;
        try {
            ret = run.apply(null, [this]);
        } catch (error) {
            throw error;
        } finally {
            this.__context_handle.pop();
        }

        return ret;
    }
}


export class StoreProxyHandler<T extends object> implements ProxyHandler<T> {

}


export class StoreDecBuilder {

    private __module_item: StoreOptions<StateType>;// | Module<StateType, StateType>;
    private __store_item: StoreItem

    constructor() {
        this.__module_item = {};
        this.__store_item = new StoreItem();
        this.__store_item.__root_object = new StoreItem();
    }

    get output() {
        return {
            module_item: this.__module_item,
            store_item: this.__store_item
        }
    }

    __appendState(state_name: string, value: any) {
        if (!this.__module_item.state) {
            this.__module_item.state = new StateType();
        }

        // console.log(`__appendState(${state_name}, ${value})`)

        // 设置状态
        if (this.__module_item.state instanceof StateType) {
            this.__module_item.state[state_name] = value;
        }

        // 状态提交调用
        Reflect.defineProperty(this.__store_item, state_name, {
            configurable: false,
            enumerable: false,
            get(this: StoreItem) {
                let ret: any;
                if (this.__context) {
                    ret = this.__context.state[state_name];
                } else if (this.__state) {
                    ret = this.__state[state_name];
                }
                else {
                    throw new Error(`未知错误，请先确认是否正确使用并初始化。`);
                }
                return ret;
            },
            set(this: StoreItem, value: any) {
                if (this.__context) {
                    this.__context.state[state_name] = value;
                } else if (this.__state) {
                    throw new Error(`请不要在外部修改状态。[${this.__path}.${state_name}]`);
                }
                else {
                    throw new Error(`未知错误，请先确认是否正确使用并初始化。`);
                }
            }
        });

        if (this.__store_item.__root_object) {
            Reflect.defineProperty(this.__store_item.__root_object, state_name, {
                configurable: false,
                enumerable: false,
                get(this: StoreItem) {
                    let ret: any;
                    if (this.__rootState) {
                        ret = this.__rootState[state_name];
                    }
                    else {
                        throw new Error(`不正确调用，请先确认是否正确使用并初始化。`);
                    }
                    return ret;
                },
                set(this: StoreItem, value: any) {
                    throw new Error(`请不要在外部修改状态。from root[${this.__path}.${state_name}]`);
                }
            });
        }


    }

    /**
     * 生成定义器
     * @param setter_name 被定义的设置器的名字
     * @param setter 被定义的设置器方法
     */
    __appendMutation(setter_name: string, setter: (payload?: any) => void) {
        if (!this.__module_item.mutations) {
            this.__module_item.mutations = {};
        }

        // 设置提交
        this.__module_item.mutations[setter_name] = (state: StateType, payload?: any) => {
            this.__store_item.__with(
                { state },
                _store_item => setter.apply(_store_item, [payload])
            );
        };

        // 状态提交调用
        Reflect.defineProperty(this.__store_item, setter_name, {
            configurable: false,
            enumerable: false,
            set(this: StoreItem, payload?: any) {
                if (this.__context) {
                    this.__context.commit(setter_name, payload);
                } else if (this.__store) {
                    this.__store.commit(this.__path + setter_name, payload);
                }
            }
        });

        if (this.__store_item.__root_object) {
            Reflect.defineProperty(this.__store_item.__root_object, setter_name, {
                configurable: false,
                enumerable: false,
                set(this: StoreItem, payload?: any) {
                    if (this.__context) {
                        this.__context.commit(this.__path + setter_name, payload, { root: true });
                    } else if (this.__store) {
                        this.__store.commit(this.__path + setter_name, payload);
                    }
                }
            });
        }

    }

    /**
     * 生成获取器
     * @param getter_name 被定义的获取器的名字
     * @param getter 被定义的获取器方法
     */
    __appendGetter(getter_name: string, getter: () => any) {
        if (!this.__module_item.getters) {
            this.__module_item.getters = {};
        }

        // 设置获取器
        this.__module_item.getters[getter_name] = (
            state: StateType,
            getters: any,
            rootState: any,
            rootGetters: any
        ) => {
            return this.__store_item.__with(
                { state, getters, rootState, rootGetters },
                store_item => getter.apply(store_item)
            );
        };

        // 获取器调用
        Reflect.defineProperty(this.__store_item, getter_name, {
            configurable: false,
            enumerable: false,
            get(this: StoreItem) {
                let ret: any;
                if (this.__context) {
                    ret = this.__context.getters[getter_name];
                } else if (this.__store) {
                    ret = this.__store.getters[this.__path + getter_name];
                }
                return ret;
            }
        });

        if (this.__store_item.__root_object) {
            Reflect.defineProperty(this.__store_item.__root_object, getter_name, {
                configurable: false,
                enumerable: false,
                get(this: StoreItem) {
                    let ret: any;
                    if (this.__context) {
                        ret = this.__context.rootGetters[this.__path + getter_name];
                    } else if (this.__store) {
                        ret = this.__store.getters[this.__path + getter_name];
                    }
                    return ret;
                }
            });
        }
    }

    /**
     * 生成操作处理
     * @param action_name 被定义操作的名字
     * @param action 被定义操作
     */
    __appendAction(action_name: string, action: (payload?: any) => any) {
        if (!this.__module_item.actions) {
            this.__module_item.actions = {};
        }

        // (this: Store<R>, injectee: ActionContext<S, R>, payload?: any) => any
        // 设置 action
        this.__module_item.actions[action_name] = (
            injectee: ActionContext<StateType, StateType>,
            payload?: any
        ) => {
            return this.__store_item.__with(
                {
                    state: injectee.state,
                    getters: injectee.getters,
                    rootState: injectee.rootState,
                    rootGetters: injectee.rootGetters,
                    commit: injectee.commit,
                    dispatch: injectee.dispatch
                },
                _store_item => action.apply(_store_item, payload)
            );
        };

        // 操作调用
        Reflect.defineProperty(this.__store_item, action_name, {
            configurable: false,
            enumerable: false,
            writable: false,
            value: function (this: StoreItem, payload?: any) {
                let ret: Promise<any> | undefined;
                if (this.__context) {
                    ret = this.__context.dispatch(action_name, payload);
                } else if (this.__store) {
                    ret = this.__store.dispatch(this.__path + action_name, payload);
                } else {
                    console.log(`使用了不正常的方式调用了 action:[${this.__path + action_name}]`);
                }
                return ret || new Promise((resolve, reject) => reject());
            }
        });

        if (this.__store_item.__root_object) {
            Reflect.defineProperty(this.__store_item.__root_object, action_name, {
                configurable: false,
                enumerable: false,
                writable: false,
                value: function (this: StoreItem, payload?: any) {
                    let ret: Promise<any> | undefined;
                    if (this.__context) {
                        ret = this.__context.dispatch(action_name, payload, { root: true });
                    } else if (this.__store) {
                        ret = this.__store.dispatch(this.__path + action_name, payload);
                    } else {
                        console.log(`使用了不正常的方式调用了 action:[${this.__path + action_name}]`);
                    }
                    return ret || new Promise((resolve, reject) => reject());
                }
            });
        }
    }

    /** 添加子模块 */
    __appendModule(module_name: string, store_item: StoreItem, module_item: Module<any, any>) {

        // vuex 状态的模块注册
        if (!this.__module_item.modules) {
            this.__module_item.modules = {};
        }
        module_item.namespaced = true;
        this.__module_item.modules[module_name] = module_item;

        // 当前模块关联
        store_item.__parent = this.__store_item;
        store_item.__store_name = module_name;
        Reflect.defineProperty(this.__store_item, module_name, {
            configurable: false,
            enumerable: false,
            writable: false,
            value: store_item
        });
        this.__store_item.__children.push(store_item);

        // 根引用的模块关联
        if (this.__store_item.__root_object && store_item.__root_object) {
            let p_item = this.__store_item.__root_object;
            let c_item = store_item.__root_object;

            c_item.__parent = p_item;
            c_item.__store_name = module_name;
            Reflect.defineProperty(p_item, module_name, {
                configurable: false,
                enumerable: false,
                writable: false,
                value: c_item
            });
            p_item.__children.push(c_item);
        }
    }
}
